package com.joker.airoleplayplatformback.service.impl;

import com.joker.airoleplayplatformback.domain.dto.ChatSessionInfoDTO;
import com.joker.airoleplayplatformback.domain.dto.VoiceResponse;
import com.joker.airoleplayplatformback.domain.event.VoiceProcessingEvent;
import com.joker.airoleplayplatformback.domain.po.AiAgentPO;
import com.joker.airoleplayplatformback.domain.po.ChatSessionPO;
import com.joker.airoleplayplatformback.listener.VoiceProcessingListener;
import com.joker.airoleplayplatformback.service.AiAgentService;
import com.joker.airoleplayplatformback.service.ChatService;
import com.joker.airoleplayplatformback.service.VoiceChatService;
import com.joker.airoleplayplatformback.utils.VoiceTypeListUtils;
import com.joker.airoleplayplatformback.utils.WavFileUtils;
import com.joker.airoleplayplatformback.websocket.VoiceChatWebSocketHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 语音聊天服务实现类
 *
 * @author feixiang.li
 * @since 2025-09-27
 */
@Slf4j
@Service
public class VoiceChatServiceImpl implements VoiceChatService {

    @Autowired
    private AiAgentService aiAgentService;

    @Autowired
    private ChatService chatService;

    @Autowired
    private ApplicationEventPublisher eventPublisher;

    @Autowired
    private VoiceProcessingListener voiceProcessingListener;

    @Value("${langchain4j.open-ai.chat-model.api-key}")
    private String apiKey;

    // 存储WebSocket会话对应的聊天信息
    private final Map<String, ChatSessionInfoDTO> sessionInfoMap = new ConcurrentHashMap<>();

    // 存储音频流数据
    private final Map<String, List<byte[]>> audioStreamMap = new ConcurrentHashMap<>();

    @Override
    public void initChatSession(String websocketSessionId, Long userId, String agentId, String chatSessionId) {
        try {
            AiAgentPO agent = aiAgentService.getAgentById(Long.valueOf(agentId));
            if (agent == null) {
                throw new RuntimeException("智能体不存在");
            }

            ChatSessionInfoDTO sessionInfo = new ChatSessionInfoDTO();
            sessionInfo.setUserId(userId);
            sessionInfo.setAgent(agent);
            sessionInfo.setChatSessionId(chatSessionId);

            // 如果是新会话，创建会话记录
            if (chatSessionId == null || "new".equals(chatSessionId)) {
                ChatSessionPO newSession = chatService.createNewSession(userId, Long.valueOf(agentId));
                sessionInfo.setChatSessionId(newSession.getSessionId());
            }

            sessionInfoMap.put(websocketSessionId, sessionInfo);

            // 注册会话信息到监听器
            VoiceProcessingListener.ChatSessionInfoDTO listenerSessionInfo = new VoiceProcessingListener.ChatSessionInfoDTO();
            listenerSessionInfo.setUserId(userId);
            listenerSessionInfo.setAgent(agent);
            listenerSessionInfo.setChatSessionId(sessionInfo.getChatSessionId());
            voiceProcessingListener.registerSessionInfo(websocketSessionId, listenerSessionInfo);

            log.info("聊天会话初始化成功: websocket={}, user={}, agent={}", websocketSessionId, userId, agent.getName());

        } catch (Exception e) {
            log.error("初始化聊天会话失败", e);
            throw e;
        }
    }

    @Override
    public void processAudioStream(String websocketSessionId, byte[] audioData, VoiceChatWebSocketHandler handler) {
        // 将音频数据添加到流缓存中
        audioStreamMap.computeIfAbsent(websocketSessionId, k -> new ArrayList<>()).add(audioData);
        log.info("收到音频流数据: session={}, size={} bytes", websocketSessionId, audioData.length);
        
        // 检查音频数据是否有效
        if (audioData.length == 0) {
            log.warn("收到空的音频数据: session={}", websocketSessionId);
        } else {
            log.debug("音频数据前10字节: {}", java.util.Arrays.toString(java.util.Arrays.copyOfRange(audioData, 0, Math.min(10, audioData.length))));
        }
    }

    @Override
    public void finishAudioRecording(String websocketSessionId) {
        try {
            List<byte[]> audioChunks = audioStreamMap.remove(websocketSessionId);
            if (audioChunks == null || audioChunks.isEmpty()) {
                log.warn("没有音频数据可处理: {}", websocketSessionId);
                return;
            }

            // 合并音频数据
            int totalSize = audioChunks.stream().mapToInt(chunk -> chunk.length).sum();
            byte[] completeAudio = new byte[totalSize];
            int offset = 0;
            for (byte[] chunk : audioChunks) {
                System.arraycopy(chunk, 0, completeAudio, offset, chunk.length);
                offset += chunk.length;
            }

            // 保存音频文件 - 使用WAV格式
            String audioFileName = "voice_" + UUID.randomUUID() + ".wav";
            String tempFilePath = System.getProperty("java.io.tmpdir") + File.separator + audioFileName;

            // 使用WAV文件工具创建标准WAV文件
            boolean success = WavFileUtils.convertToWav(completeAudio, tempFilePath);
            
            if (!success) {
                log.error("WAV文件创建失败: {}", tempFilePath);
                return;
            }

            log.info("WAV音频文件保存成功: {}, size: {} bytes, chunks: {}", tempFilePath, completeAudio.length, audioChunks.size());
            
            // 验证WAV文件
            if (WavFileUtils.isValidWavFile(tempFilePath)) {
                WavFileUtils.WavFileInfo wavInfo = WavFileUtils.getWavFileInfo(tempFilePath);
                if (wavInfo != null) {
                    log.info("WAV文件信息: {}", wavInfo);
                }
            } else {
                log.warn("WAV文件格式验证失败: {}", tempFilePath);
            }

            // 发布事件，异步处理完整音频
            VoiceProcessingEvent event = new VoiceProcessingEvent(this, websocketSessionId, tempFilePath);
            eventPublisher.publishEvent(event);

            log.info("语音处理事件已发布: websocketSessionId={}", websocketSessionId);

        } catch (Exception e) {
            log.error("处理音频录制失败", e);
        }
    }

    @Override
    public void processCompleteAudio(String websocketSessionId, String audioFilePath) {
        // 发布事件，由监听器异步处理
        VoiceProcessingEvent event = new VoiceProcessingEvent(this, websocketSessionId, audioFilePath);
        eventPublisher.publishEvent(event);
        log.info("语音处理事件已发布: websocketSessionId={}, audioFile={}", websocketSessionId, audioFilePath);
    }


    /**
     * 注册WebSocket处理器（保留接口兼容性，实际由WebSocketConnectionManager管理）
     */
    @Override
    public void registerHandler(String websocketSessionId, VoiceChatWebSocketHandler handler) {
        // 处理器注册由WebSocketConnectionManager管理，这里只记录日志
        log.debug("WebSocket处理器注册: {}", websocketSessionId);
    }

    /**
     * 移除WebSocket处理器
     */
    @Override
    public void unregisterHandler(String websocketSessionId) {
        sessionInfoMap.remove(websocketSessionId);

        // 从监听器中移除会话信息
        voiceProcessingListener.unregisterSessionInfo(websocketSessionId);

        log.info("WebSocket处理器和会话信息已清理: {}", websocketSessionId);
    }

    /**
     * 获取音色列表
     *
     * @return VoiceResponse 音色列表响应
     */
    @Override
    public VoiceResponse getVoiceTypeList() {
        return VoiceTypeListUtils.getVoiceList(apiKey);
    }

    /**
     * 供监听器调用的获取处理器方法（已废弃，使用WebSocketConnectionManager）
     */
    @Deprecated
    public VoiceChatWebSocketHandler getHandler(String websocketSessionId) {
        // 此方法已废弃，WebSocket连接管理已移至WebSocketConnectionManager
        log.warn("getHandler方法已废弃，请使用WebSocketConnectionManager");
        return null;
    }

    @Override
    public void processVoiceFile(String websocketSessionId, String audioFilePath) {
        try {
            log.info("开始处理语音文件: websocketSessionId={}, audioFilePath={}", websocketSessionId, audioFilePath);
            
            // 发布语音处理事件，使用现有的异步处理流程
            VoiceProcessingEvent event = new VoiceProcessingEvent(this, websocketSessionId, audioFilePath);
            eventPublisher.publishEvent(event);
            
            log.info("语音处理事件已发布: websocketSessionId={}", websocketSessionId);
            
        } catch (Exception e) {
            log.error("处理语音文件失败: websocketSessionId={}, audioFilePath={}", websocketSessionId, audioFilePath, e);
            throw new RuntimeException("处理语音文件失败", e);
        }
    }

    @Override
    public byte[] processMp3File(String mp3FilePath, String userId, String agentId, String sessionId) {
        try {
            log.info("开始处理MP3文件: mp3FilePath={}, userId={}, agentId={}, sessionId={}", 
                    mp3FilePath, userId, agentId, sessionId);

            // 1. 验证文件存在
            File mp3File = new File(mp3FilePath);
            if (!mp3File.exists() || mp3File.length() == 0) {
                throw new RuntimeException("MP3文件不存在或为空: " + mp3FilePath);
            }

            // 2. 获取智能体信息
            AiAgentPO agent = aiAgentService.getAgentById(Long.parseLong(agentId));
            if (agent == null) {
                throw new RuntimeException("智能体不存在: " + agentId);
            }

            // 3. 获取会话信息
            ChatSessionPO session = chatService.getSession(sessionId);
            if (session == null) {
                throw new RuntimeException("会话不存在: " + sessionId);
            }

            // 4. 上传MP3文件到OSS (这里需要注入OssService)
            // String audioUrl = ossService.uploadFile(mp3File, "voice/" + mp3File.getName());

            // 5. 调用ASR进行语音识别 (这里需要注入相关服务)
            // String recognizedText = speechRecognitionService.recognize(audioUrl);

            // 6. 调用AI生成回复
            // String aiReply = aiService.generateReply(recognizedText, agent, session);

            // 7. 调用TTS生成语音
            // byte[] aiAudioData = ttsService.textToSpeech(aiReply, agent.getDefaultVoiceType());

            // 暂时返回示例数据，实际实现需要完整的处理流程
            log.warn("MP3文件处理功能暂未完全实现，返回空数据");
            return new byte[0];

        } catch (Exception e) {
            log.error("处理MP3文件失败: mp3FilePath={}", mp3FilePath, e);
            throw new RuntimeException("处理MP3文件失败", e);
        }
    }


}
